package org.xtense.engine.actions;

import java.text.MessageFormat;
import java.util.Iterator;
import java.util.List;

import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Node;
import org.xtense.data.DBManager;
import org.xtense.engine.IConstants;
import org.xtense.engine.SimpleQueryParser;
import org.xtense.engine.XtenseFactory;
import org.xtense.exception.XtenseException;
import org.xtense.log.iLog;
import org.xtense.model.CSubSet;

/**
 * 
 * @author Administrator
 *
 */
public class QueryAction extends XAction {
	private XtenseFactory factory;

	public QueryAction(String documentName) {
		this(new DBManager(), documentName);
	}
	
	/**
	 * Constructor
	 * @param manager
	 * @param documentName
	 */
	public QueryAction(DBManager manager, String documentName) {
		super(manager, documentName);
		factory = XtenseFactory.instance();
		documentID = super.getDocumentIDfromName(manager, documentName);
		if (documentID < 0) {
			try {
				throw new XtenseException(XtenseException.NoSuchDoc);
			} catch (XtenseException e) {
				iLog.warn(e);
			}
		}
		// for update action
		new UpdateAction(database, documentID);
	}

	/**
	 * Constructor
	 * @param manager
	 * @param documentID
	 */
	public QueryAction(DBManager manager, int documentID) {
		super(manager, documentID);
		factory = XtenseFactory.instance();
		// for update action
		new UpdateAction(database, documentID);
	}

	@SuppressWarnings("unchecked")
	public Object execute(Object object) {
		SimpleQueryParser parser = new SimpleQueryParser(documentID, object
				.toString());

		// select elementPre sql
		String elemIn = MessageFormat.format(IConstants.Sql_IN, new Object[] {
				IConstants.Element_Pre, parser.getPathQuery() });
		String andTwo = MessageFormat.format(IConstants.Sql_Int_Equal,
				new Object[] { IConstants.Document_ID, documentID });
		

		if (parser.queryForAttribute()) {
			String attrEq = MessageFormat.format(
					IConstants.Sql_String_Equal, new Object[] {
							IConstants.Attribute_Name,
							parser.getAttributeName() });
			andTwo = MessageFormat.format(IConstants.Sql_And, new Object[] {
					attrEq, andTwo });
		}
		iLog.info("Query...");
		CSubSet tempResult = getResult(elemIn, andTwo, parser
				.queryForAttribute());
		List<Node> list;
		if (parser.getAdvancedPath() == null) {
			// got the final result
			list = tempResult.getResultSet();
		} else {
			// just the temp result
			Element root;
			if (tempResult.isCompleteDocument()) {
				root = (Element) tempResult.getResultSet().get(0);
			} else {
				// wrap with a root element
				root = DocumentHelper.createElement(IConstants.tempRoot);
				Iterator<Node> iter = tempResult.getResultSet().iterator();
				while (iter.hasNext()) {
					root.add(iter.next());
				}
			}
			Document d = DocumentHelper.createDocument(root);
			list = d.selectNodes(parser.getAdvancedPath());
		}
		iLog.info("Query successfully.");
		
		return list;

	}

	/**
	 * using the pattern to get data from tables.
	 * 
	 * @param pattern
	 * @return
	 */
	private CSubSet getResult(String elemIn, String andTwo,
			boolean queryForAttribute) {
		CSubSet result = factory.createResultSetForQuery(documentID);
		String sql;
		if (queryForAttribute) {
			sql = MessageFormat.format(IConstants.Sql_Select_Two, new Object[] {
					"*", IConstants.Attribute_Table, elemIn, andTwo });
			factory.generateResulte(result, database.executeSqlQuery(sql),
					IConstants.ATTRIBUTE);
		} else {
			for (Iterator<Integer> iterator = IConstants.AETPtables.keySet()
					.iterator(); iterator.hasNext();) {
				int i = iterator.next().intValue();
				sql = MessageFormat.format(IConstants.Sql_Select_Two,
						new Object[] { "*", IConstants.AETPtables.get(i),
								elemIn, andTwo });
				factory.generateResulte(result, database.executeSqlQuery(sql),
						i);
			}
		}
		return result;
	}
}
